/**
 * @p.md
 * 
 * 此示例展示如何使用 SQLite 提供者来持久化 Actor 状态
 */

import {
  ActorSystem,
  Props,
  PID
} from '../src/actor';

import {
  PersistentActor,
  RecoverContext,
  CommandContext,
  EventType,
  PersistenceFactory,
  RecoveryStrategy,
  SQLiteProvider
} from '../src/persistence';

/**
 * 计数器命令类型
 */
enum CounterCommandType {
  Increment = 'increment',
  Decrement = 'decrement',
  GetCount = 'get-count',
  Reset = 'reset',
  CreateSnapshot = 'create-snapshot'
}

/**
 * 计数器事件类型
 */
enum CounterEventType {
  Incremented = 'incremented',
  Decremented = 'decremented',
  Reset = 'reset'
}

/**
 * 计数器命令接口
 */
interface CounterCommand {
  type: CounterCommandType;
  amount?: number;
}

/**
 * 计数器事件接口
 */
interface CounterEvent {
  type: CounterEventType;
  amount?: number;
}

/**
 * 计数器状态接口
 */
interface CounterState {
  count: number;
}

/**
 * 持久化计数器 Actor
 */
class PersistentCounterActor extends PersistentActor {
  // 持久化 ID
  private _persistenceId: string;
  
  // 当前计数
  private count: number = 0;
  
  // 事件索引
  private eventIndex: number = 0;
  
  // 最后快照索引
  private lastSnapshotIndex: number = 0;
  
  // 快照间隔（事件数量）
  private readonly snapshotInterval: number = 10;
  
  /**
   * 构造函数
   * @param id 计数器 ID
   */
  constructor(id: string) {
    super();
    this._persistenceId = `counter-${id}`;
  }
  
  /**
   * 获取持久化 ID
   */
  get persistenceId(): string {
    return this._persistenceId;
  }
  
  /**
   * 恢复事件处理
   * @param context 恢复上下文
   */
  receiveRecover(context: RecoverContext): void {
    const eventType = context.eventType;
    const event = context.event;
    
    if (eventType === EventType.Snapshot) {
      // 从快照恢复状态
      const state = event as CounterState;
      this.count = state.count;
      console.log(`[${this.persistenceId}] 从快照恢复状态: count = ${this.count}`);
    } else if (eventType === EventType.Event) {
      // 从事件恢复状态
      this.applyEvent(event as CounterEvent);
      this.eventIndex = context.eventIndex;
      console.log(`[${this.persistenceId}] 从事件恢复状态: index = ${this.eventIndex}, count = ${this.count}`);
    }
  }
  
  /**
   * 命令处理
   * @param context 命令上下文
   */
  receiveCommand(context: CommandContext): void {
    const command = context.message() as CounterCommand;
    
    switch (command.type) {
      case CounterCommandType.Increment:
        const incrementAmount = command.amount || 1;
        const incrementEvent: CounterEvent = {
          type: CounterEventType.Incremented,
          amount: incrementAmount
        };
        
        // 持久化增量事件
        context.persist(incrementEvent).then(() => {
          this.eventIndex++;
          this.applyEvent(incrementEvent);
          context.respond({ count: this.count });
          
          // 检查是否需要创建快照
          this.checkSnapshot(context);
        });
        break;
        
      case CounterCommandType.Decrement:
        const decrementAmount = command.amount || 1;
        const decrementEvent: CounterEvent = {
          type: CounterEventType.Decremented,
          amount: decrementAmount
        };
        
        // 持久化减量事件
        context.persist(decrementEvent).then(() => {
          this.eventIndex++;
          this.applyEvent(decrementEvent);
          context.respond({ count: this.count });
          
          // 检查是否需要创建快照
          this.checkSnapshot(context);
        });
        break;
        
      case CounterCommandType.Reset:
        const resetEvent: CounterEvent = {
          type: CounterEventType.Reset
        };
        
        // 持久化重置事件
        context.persist(resetEvent).then(() => {
          this.eventIndex++;
          this.applyEvent(resetEvent);
          context.respond({ count: this.count });
          
          // 检查是否需要创建快照
          this.checkSnapshot(context);
        });
        break;
        
      case CounterCommandType.GetCount:
        // 只读操作，不需要持久化
        context.respond({ count: this.count });
        break;
        
      case CounterCommandType.CreateSnapshot:
        // 手动创建快照
        this.takeSnapshot(context);
        break;
        
      default:
        console.log(`[${this.persistenceId}] 未知命令: ${JSON.stringify(command)}`);
        break;
    }
  }
  
  /**
   * 应用事件到状态
   * @param event 事件
   */
  private applyEvent(event: CounterEvent): void {
    switch (event.type) {
      case CounterEventType.Incremented:
        this.count += event.amount || 1;
        console.log(`[${this.persistenceId}] 增加计数: ${event.amount || 1}, 当前计数: ${this.count}`);
        break;
        
      case CounterEventType.Decremented:
        this.count -= event.amount || 1;
        console.log(`[${this.persistenceId}] 减少计数: ${event.amount || 1}, 当前计数: ${this.count}`);
        break;
        
      case CounterEventType.Reset:
        this.count = 0;
        console.log(`[${this.persistenceId}] 重置计数`);
        break;
    }
  }
  
  /**
   * 检查是否需要创建快照
   * @param context 命令上下文
   */
  private checkSnapshot(context: CommandContext): void {
    if (this.eventIndex - this.lastSnapshotIndex >= this.snapshotInterval) {
      this.takeSnapshot(context);
    }
  }
  
  /**
   * 创建快照
   * @param context 命令上下文
   */
  private takeSnapshot(context: CommandContext): void {
    const state: CounterState = {
      count: this.count
    };
    
    context.snapshot(state).then(() => {
      this.lastSnapshotIndex = this.eventIndex;
      console.log(`[${this.persistenceId}] 创建快照: count = ${this.count}, index = ${this.eventIndex}`);
    });
  }
  
  /**
   * 恢复完成回调
   * @param context 上下文
   */
  protected onRecoveryCompleted(context: any): void {
    console.log(`[${this.persistenceId}] 恢复完成: count = ${this.count}, eventIndex = ${this.eventIndex}`);
  }
}

/**
 * 运行 SQLite 示例
 */
async function runSQLiteExample() {
  console.log('开始 SQLite 持久化示例');
  
  // 创建 Actor 系统
  const system = new ActorSystem();
  
  // 获取持久化工厂
  const persistenceFactory = PersistenceFactory.getInstance();
  
  // 创建 SQLite 持久化提供者
  // 这里使用内存模式的 SQLite 数据库，实际应用中可以指定文件路径
  const sqliteProvider = persistenceFactory.createSQLiteProvider(':memory:', 'sqlite-example');
  
  // 创建持久化 Actor 属性
  const props = persistenceFactory.persistentProps(
    () => new PersistentCounterActor('1'),
    'sqlite-example',
    {
      recoveryStrategy: RecoveryStrategy.SnapshotThenEvents,
      snapshotInterval: 10,
      eventsBatchSize: 100
    }
  );
  
  // 创建 Actor
  const counterPid = system.root.spawn(props);
  console.log(`创建计数器 Actor: ${counterPid.id}`);
  
  // 发送命令并接收响应
  await sendCommand(system, counterPid, { type: CounterCommandType.Increment, amount: 5 });
  await sendCommand(system, counterPid, { type: CounterCommandType.Increment, amount: 3 });
  await sendCommand(system, counterPid, { type: CounterCommandType.GetCount });
  await sendCommand(system, counterPid, { type: CounterCommandType.Decrement, amount: 2 });
  await sendCommand(system, counterPid, { type: CounterCommandType.GetCount });
  
  // 创建快照
  await sendCommand(system, counterPid, { type: CounterCommandType.CreateSnapshot });
  
  // 继续发送命令
  await sendCommand(system, counterPid, { type: CounterCommandType.Increment, amount: 10 });
  await sendCommand(system, counterPid, { type: CounterCommandType.GetCount });
  
  // 停止 Actor
  system.root.stop(counterPid);
  console.log(`停止计数器 Actor: ${counterPid.id}`);
  
  // 重新创建同一个 Actor（会从 SQLite 恢复状态）
  console.log('重新创建计数器 Actor（从 SQLite 恢复状态）');
  const restoredCounterPid = system.root.spawn(props);
  
  // 获取恢复后的状态
  await new Promise(resolve => setTimeout(resolve, 100)); // 等待恢复完成
  await sendCommand(system, restoredCounterPid, { type: CounterCommandType.GetCount });
  
  // 继续发送命令
  await sendCommand(system, restoredCounterPid, { type: CounterCommandType.Increment, amount: 1 });
  await sendCommand(system, restoredCounterPid, { type: CounterCommandType.GetCount });
  
  // 重置计数
  await sendCommand(system, restoredCounterPid, { type: CounterCommandType.Reset });
  await sendCommand(system, restoredCounterPid, { type: CounterCommandType.GetCount });
  
  // 停止 Actor
  system.root.stop(restoredCounterPid);
  
  console.log('SQLite 持久化示例结束');
}

/**
 * 发送命令并打印响应
 * @param system Actor 系统
 * @param pid 目标 PID
 * @param command 命令
 */
async function sendCommand(system: ActorSystem, pid: PID, command: CounterCommand): Promise<void> {
  console.log(`发送命令: ${JSON.stringify(command)}`);
  
  if (command.type === CounterCommandType.CreateSnapshot) {
    system.root.send(pid, command);
    await new Promise(resolve => setTimeout(resolve, 100)); // 等待快照创建完成
  } else {
    const response = await system.root.requestFuture(pid, command, 1000);
    console.log(`收到响应: ${JSON.stringify(response)}`);
  }
}

/**
 * 运行示例
 */
async function runExample() {
  try {
    await runSQLiteExample();
  } catch (error) {
    console.error('示例运行出错:', error);
  }
}

// 执行示例
runExample().catch(console.error); 